package ssh

import (
	"errors"
	"fmt"
	"regexp"
	"strconv"
	"time"
)

var numberRegexp = regexp.MustCompile(`\d+`)

// Pidof 根据进程名查询进程 ID
func (own *Client) Pidof(names ...string) (map[string][]int, error) {
	pidMap := make(map[string][]int)
	for _, name := range names {
		res, err := own.Execute("pidof " + name)
		if err != nil {
			if err, ok := IsExitError(err); ok && err.ExitStatus() == 1 {
				continue
			}

			return nil, err
		}

		pidMap[name] = FormatStringSliceToIntSlice(numberRegexp.FindAllString(res, -1))
	}

	return pidMap, nil
}

// Killall 根据进程名杀进程
func (own *Client) Killall(names ...string) error {
	for _, name := range names {
		if res, err := own.Execute("killall -9 " + name); err != nil {
			return err
		} else if len(res) > 3 {
			return errors.New(res)
		}
	}

	return nil
}

// Kill 根据进程 ID 杀进程
func (own *Client) Kill(pids ...int) error {
	for _, pid := range pids {
		if res, err := own.Execute("kill -9 " + strconv.Itoa(pid)); err != nil {
			return err
		} else if len(res) > 3 {
			return errors.New(res)
		}
	}

	return nil
}

// WaitProcesses 等待指定的所有进程启动，默认100s超时
func (own *Client) WaitProcesses(names []string, timeoutSeconds ...int64) (map[string][]int, error) {
	// 创建等待超时时间
	timeout := time.Now().Add(time.Second * 100)
	if len(timeoutSeconds) > 0 {
		timeout = time.Now().Add(time.Second * time.Duration(timeoutSeconds[0]))
	}

	// 创建计时器
	ticker := time.NewTicker(time.Second * 3)
	defer ticker.Stop()

	for {
		<-ticker.C

		// 查询指定进程
		pids, err := own.Pidof(names...)
		if err != nil {
			return nil, err
		}

		// 所有指定进程已启动
		if len(pids) == len(names) {
			return pids, nil
		}

		// 等待超时
		if time.Now().After(timeout) {
			return pids, fmt.Errorf("gokit: ssh: wait processes timeout")
		}

		// 重置计时器
		ticker.Reset(time.Second * 3)
	}
}

// func (own *Client) Ifconfig() {}

// func (own *Client) Start(timeout int64, cmds ...string) ([]string, error) {
// 	pids := make([]string, len(cmds))
// 	names := make([]string, 0, len(cmds))
// 	for idx, cmd := range cmds {
// 		// 初始化命令
// 		names = append(names, filepath.Base(strings.Split(cmd, " ")[0]))
// 		if !strings.HasSuffix(cmd, " &") {
// 			cmd = " &"
// 		}

// 		// 检查进程是否已经启动
// 		if _pids, err := own.Pidof(names[idx]); err != nil {
// 			return nil, err
// 		} else if len(_pids) > 0 {
// 			pids[idx] = _pids[0]
// 			continue
// 		}

// 		// 启动进程
// 		if _, err := own.Execute(cmd); err != nil {
// 			return nil, err
// 		}
// 	}

// 	return own.WaitProcesses(timeout, names...)
// }

// func (own *Client) Restart(timeout int64, cmds ...string) ([]string, error) {
// 	names := make([]string, 0, len(cmds))
// 	for idx, cmd := range cmds {
// 		names = append(names, filepath.Base(strings.Split(cmd, " ")[0]))
// 		if !strings.HasSuffix(cmd, " &") {
// 			cmd += " &"
// 		}

// 		// 检查进程是否已启动
// 		pids, err := own.Pidof(names[idx])
// 		if err != nil {
// 			return nil, err
// 		} else if len(pids) > 0 { // 终止进程
// 			if err := own.Kill(pids...); err != nil {
// 				return nil, err
// 			}
// 		}

// 		// 启动进程
// 		if _, err := own.Execute(cmd); err != nil {
// 			return nil, err
// 		}
// 	}

// 	return own.WaitProcesses(timeout, names...)
// }

// const SystemBinPathPrefix = "/system/bin/"

// var SystemBinMap = map[string]struct{}{
// 	"SCYService":                  {},
// 	"athelper":                    {},
// 	"atproxy":                     {},
// 	"canconfig":                   {},
// 	"candump":                     {},
// 	"canecho":                     {},
// 	"cansend":                     {},
// 	"cansequence":                 {},
// 	"cfg_wifi_mac.sh":             {},
// 	"check_io":                    {},
// 	"checkstatus.sh":              {},
// 	"cpnvram":                     {},
// 	"daemon1609dot2":              {},
// 	"deviceMonitor":               {},
// 	"dtt-proxy":                   {},
// 	"dtvl-pltest":                 {},
// 	"emsd":                        {},
// 	"export_modem_mem.sh":         {},
// 	"fg150_sim_check.sh":          {},
// 	"gnss-config":                 {},
// 	"gnssService":                 {},
// 	"gnss_server":                 {},
// 	"hostapd":                     {},
// 	"imx6_communication_check.sh": {},
// 	"initDaemon.sh":               {},
// 	"insightProxy":                {},
// 	"iptables":                    {},
// 	"lvspark.config":              {},
// 	"modemshakey":                 {},
// 	"ncs_2020":                    {},
// 	"ncs_4layer":                  {},
// 	"ncsproxy":                    {},
// 	"omCore":                      {},
// 	"omKeeper":                    {},
// 	"omLogger":                    {},
// 	"omProxy":                     {},
// 	"omProxyCustomer":             {},
// 	"proxy":                       {},
// 	"ptms":                        {},
// 	"qxwz":                        {},
// 	"rds":                         {},
// 	"rtty":                        {},
// 	"shakey":                      {},
// 	"sshpass":                     {},
// 	"startDaemon.sh":              {},
// 	"startRtty.sh":                {},
// 	"stopDaemon.sh":               {},
// 	"tcpdump":                     {},
// 	"tester":                      {},
// 	"testerproxy":                 {},
// 	"tsps":                        {},
// 	"v2x_ioctl":                   {},
// 	"v2x_perfm":                   {},
// 	"v2x_perfm_2020":              {},
// 	"v2x_perfm_4layer":            {},
// 	"v2x_recv":                    {},
// 	"v2x_send":                    {},
// 	"v2xdump":                     {},
// 	"v2xmsg":                      {},
// 	"v2xmsg_157":                  {},
// 	"v2xmsg_158":                  {},
// 	"v2xmsg_3709":                 {},
// 	"v2xmsg_53_2017":              {},
// 	"xds":                         {},
// }

// func FormatSystemBin(cmd string) string {
// 	if _, ok := SystemBinMap[strings.Split(cmd, " ")[0]]; ok {
// 		cmd = SystemBinPathPrefix + cmd
// 	}

// 	if strings.HasSuffix(cmd, " &") {
// 		return cmd
// 	}

// 	return cmd + " &"
// }

// // func formatSystemBinCommand(name string) string {
// // 	if !strings.Contains(name, "/") {
// // 		return name
// // 	}

// // }

// /*
// def get_network_addresses(self):
//         lines, err = self.execute_cmd_return_list("ifconfig")
//         if err: return None, err

//         res = {}
//         net = ""
//         for line in lines:
//             if len(line) > 0 and line[0] != " ":
//                 net = re.findall(r'^[a-zA-Z0-9]+', line)[0]
//                 continue
//             if "inet" in line:
//                 ips = re.findall(r'\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b', line)
//                 if len(ips) > 0: res[net] = ips[0]
//         return res, ""

//     def date(self, format: str = ""):
//         if format == "timestamp":
//             return self.execute_cmd_return_str(f"date +%s")
//         return self.execute_cmd_return_str(f"date")

//     def ping(self, ip: str, times: int = 5):
//         res, err = self.execute_cmd_return_list(f"ping -c {times} {ip}")
//         if err: return res, err

//         for line in res:
//             if "packet loss" in line: return float(line.split(",")[2].split("%")[0].strip()) / 100, ""
//         return 1.0, ""

//     def passwd(self, pwd: str) -> str:
//         """修改密码"""
//         err = self.mount("/")
//         if err: return err

//         res, err = self.execute_cmd_return_str("passwd", [pwd, pwd])
//         if err: return err
//         return "" if "Password for root changed" in res else res

//     def mount(self, filepath: str, mode: str = "rw") -> str:
//         res, err = self.execute_cmd_return_str(f"mount -o {mode},remount {filepath}")
//         if err: return err
//         return "" if not res else res

//     def mount_var(self) -> str:
//         """挂载并检查/var、/var/romlog、/var/ramlog"""
//         lines, err = self.execute_cmd_return_list("mount")
//         if err: return err

//         flag = False
//         for line in lines:
//             if "/var/ramlog" in line and line == "none on /var/ramlog type tmpfs (rw,relatime,size=51200k)": flag = True
//             elif "/var" in line and line == "none on /var type tmpfs (rw,relatime,size=716800k)": flag = True
//         return "" if flag else "not found '/var' or '/var/romlog' or '/var/ramlog'"

//     def touch(self, filename: str, filepath: str = "") -> str:
//         """创建文件"""
//         if not filename: return "filename not specified"
//         _, err = self.execute_cmd_return_str(f"touch {filepath}{filename}")
//         if err: return err

//         files, err = self.execute_cmd_return_list(f"find {filepath} -name {filename}")
//         if err: return err
//         return "" if len(files) > 0 else f"not found file: {filepath}{filename}"

//     def df(self, args: str = "h"):
//         """查询磁盘状态"""
//         lines, err = self.execute_cmd_return_list(f"df -{args}")
//         if err: return lines, err
//         if len(lines) < 2: return lines, "no data"
//         if "Mounted on" not in lines[0]: return lines, "fields num too few"

//         # 格式化查询结果
//         result = {}
//         items = textparser.split_lines_to_list(lines)

//         try:
//             """首行字段"""
//             line0 = items[0]
//             size = len(line0)-1
//             fields = line0[:size-1]
//             fields.append(" ".join(line0[size-1:]))

//             """处理分行数据"""
//             fs = ""
//             _items = []
//             for item in items[1:]:
//                 if len(item) == 1:
//                     fs = item[0]
//                     continue
//                 if fs:
//                     _item = [fs]
//                     _item.extend(item)
//                     item = _item
//                     fs = ""
//                 _items.append(item)

//             """解析数据"""
//             result = {}
//             for item in _items:
//                 res = {}
//                 for i in range(size-1):
//                     res[fields[i]] = item[i]
//                 result[item[-1]] =res
//             return result, ""
//         except Exception as e:
//             traceback.print_exc()
//             return "", e.__str__()

//     def ls_la(self, filepath: str):
//         """获取文件列表"""
//         lines, err = self.execute_cmd_return_list(f"ls -la --color=never {filepath}")
//         if err: return lines, err

//         files = {}
//         lines = textparser.split_lines_to_list(lines)
//         try:
//             for item in lines:
//                 if item[0].startswith("total"): continue  # total xxx
//                 if len(item) < 9: continue

//                 file_type = ""
//                 if item[0][0] == "-": file_type = "file"
//                 elif item[0][0] == "l": file_type = "link"
//                 elif item[0][0] == "d": file_type = "dir"

//                 file_name = " ".join(item[8:])
//                 if item[8][0] == "'": file_name = file_name[1:-1]
//                 files[file_name] = {
//                     "type": file_type,
//                     "auth": item[0],
//                     "num": int(item[1]),
//                     "owner": item[2],
//                     "group": item[3],
//                     "size": int(item[4]),
//                     "modify": " ".join(item[5:8])
//                 }
//             return files, ""
//         except Exception as e:
//             traceback.print_exc()
//             return "", e.__str__()

//     def pidof(self, process_name: str):
//         try:
//             lines, err = self.execute_cmd_return_list(f"pidof {process_name}")
//             if err: return "", err
//             return lines[0] if len(lines) > 0 else "", ""
//         except Exception as e:
//             traceback.print_exc()
//             return "", e.__str__()

//     def kill(self, pid, force: bool = True):
//         cmd = f"kill -9 {pid}" if force else f"kill {pid}"
//         try:
//             _, err = self.execute_cmd_return_list(cmd)
//             return err if err else ""
//         except Exception as e:
//             traceback.print_exc()
//             return e.__str__()
// */

func Filter(items []string, ignore string) []string {
	res := make([]string, 0, len(items))
	for _, item := range items {
		if item != ignore {
			res = append(res, item)
		}
	}
	return res
}
